package com.springboot.demo.filter;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.cx.item.common.cache.redis.RedisCacheTransfer;
import com.cx.item.common.request.RequestUtil;
import com.springboot.demo.model.constants.SunMiniappRedisConstants;
import com.springboot.demo.service.CustomerService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by Heavin on 2018/6/26.
 * Des  登陆过滤器
 */
@Component
@WebFilter(urlPatterns = "/*", filterName = "loginFilter")
@Order(1)
public class LoginFilter implements Filter {

    private final static Log log = LogFactory.getLog(LoginFilter.class);

    private final static List<String> regexList = new ArrayList();
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private CustomerService customerService;
    @Autowired
    private JedisConnectionFactory jedisConnectionFactory;

    {
        // 初始化忽略路径
        regexList.add(".*/comm/.*");
        regexList.add(".*/wechat/.*");
        regexList.add(".*swagger.*");
        regexList.add(".*webjars.*");
        regexList.add(".*v2.*");
        regexList.add(".*druid.*");
    }

    public void init(FilterConfig arg0) throws ServletException {

        // 初始化redis二级缓存需要的工厂对象
        RedisCacheTransfer redisCacheTransfer = new RedisCacheTransfer();
        redisCacheTransfer.setJedisConnectionFactory(jedisConnectionFactory);
        redisCacheTransfer.setRedisCacheMysqlHashKey("002redisCacheMysqlHashKey");

        // 初始化用户token
        log.info("=====================================初始化数据库用户token开始=====================================");
        long l = customerService.initCustomerToken();
        log.info("<===================================初始化数据库用户token结束,redis token数量" + l + "====================================");
    }

    public void destroy() {

    }

    public void doFilter(ServletRequest arg0, ServletResponse arg1,
                         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) arg0;
        HttpServletResponse httpResponse = (HttpServletResponse) arg1;
        // 获得用户请求的URI
        String path = httpRequest.getRequestURI();

        // 请求地址参数info级别打印
        Map<String, String> paramMap = ServletUtil.getParamMap(httpRequest);
        log.info(StrFormatter.format("<====>param----请求地址：{}?{}", httpRequest.getRequestURI(), MapUtil.join(paramMap, "&", "=")));

        boolean needLogin = true;

        //如果是白名单页面  直接返回true，  其他返回false  进入下面的token验证
        for (String reg : regexList) {
            if (path.matches(reg)) {
                // 此匹配成功，则代表不需要登陆
                needLogin = false;
                break;
            }
        }

        if (needLogin) {
            needLogin(httpRequest, httpResponse, filterChain);
        } else {
            filterChain.doFilter(arg0, arg1);
        }
    }

    private void needLogin(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain filterChain) throws IOException, ServletException {

        // 请求用户token
        String tokenStr = httpRequest.getHeader(SunMiniappRedisConstants.CUSTOMER_HEAD_TOKEN_KEY);

        log.debug("=====================用户登录token====================【" + tokenStr);
        if (!StringUtils.isEmpty(tokenStr)) {
            // 拿token 去redis找  如果找到了  而且没有过期 则刷新过期时间 然后返回出去
            if (!redisTemplate.opsForHash().hasKey(SunMiniappRedisConstants.CUSTOMER_CACHE_REDIS_TOKEN_KEY, tokenStr)) {
                // token 不存在
                log.debug(StrUtil.format("========token[{}]不存在", tokenStr));
                onTokenInvalide(httpRequest, httpResponse);
                return;
            } else {

                // token验证通过

                // 验证是否重复请求
                if (RequestUtil.validateUserRequestIsRepeat(tokenStr,"001api", redisTemplate, httpRequest)){
                    httpRequest.getRequestDispatcher("/comm/repeatRequest").forward(httpRequest, httpResponse);
                    return;
                }

                // 设置用户id
                String tokenStrVal = (String) redisTemplate.opsForHash().get(SunMiniappRedisConstants.CUSTOMER_CACHE_REDIS_TOKEN_KEY, tokenStr);
                String customerId = tokenStrVal.split("_")[0];
                httpRequest.setAttribute(SunMiniappRedisConstants.CUSTOMER_ID_ATTRIBUTE_KEY, customerId);
                filterChain.doFilter(httpRequest, httpResponse);
            }
        } else {
            // token验证出错
            log.debug("==============token验证出错==================");
            onTokenInvalide(httpRequest, httpResponse);
        }
    }

    private void onTokenInvalide(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        request.getRequestDispatcher("/comm/tokenerror").forward(request, response);
    }
}